package normalisation;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.regex.Pattern;

public class Normalizer {

    public static enum NormalisationType {

        Tokenisation, Racinisation, NGram
    }

    public static enum EncodageType {

        UTF_8, ISO_8859_1
    }
    protected NormalisationType normalisation;
    protected EncodageType encodage;
    protected Boolean filterAccents;
    protected Boolean filterPonctuation;
    protected Boolean filterNombres;
    protected Boolean filterStopWords;
    protected String stopWordsFilePath;
    protected Boolean filterOneOccurence;
    protected Boolean replaceUrls;
    protected Boolean removeTags;
    protected String replaceUrlsBy;
    protected ArrayList<String> stopWordList;

    public Normalizer(NormalisationType normalisation,
            EncodageType encodage,
            Boolean filterAccents,
            Boolean filterPonctuation,
            Boolean filterNombres,
            Boolean filterStopWords,
            String stopWordsFilePath,
            Boolean filterOneOccurence,
            Boolean removeTags,
            Boolean replaceUrls,
            String replaceUrlsBy) {

        this.normalisation = normalisation;
        this.encodage = encodage;
        this.filterAccents = filterAccents;
        this.filterPonctuation = filterPonctuation;
        this.filterNombres = filterNombres;
        this.filterStopWords = filterStopWords;
        this.stopWordsFilePath = stopWordsFilePath;
        this.filterOneOccurence = filterOneOccurence;
        this.removeTags = removeTags;
        this.replaceUrls = replaceUrls;
        this.replaceUrlsBy = replaceUrlsBy;

        ArrayList<String> stopWordList = null;
    }

    public String getCharset() {
        if (encodage == EncodageType.ISO_8859_1) {
            return "ISO8859_1";
        }

        return "UTF8";
    }

    public Boolean getFilterOneOccurence() {
        return filterOneOccurence;
    }

    public ArrayList<String> normalize(String text) {

        //Replacage des url avant toute normalisation
        if (replaceUrls) {
            text = remplaceUrlsBy(text, replaceUrlsBy);

        }

        //Suppression des tags (débutent par # ou @)
        if (removeTags) {
            text = removeTags(text);
        }

        ArrayList<String> result = new ArrayList<String>();

        //Tokenisation, Racinisation, ou Lemmatisation
        if (normalisation == NormalisationType.NGram) {
            //TODO
        } else if (normalisation == NormalisationType.Racinisation) {
            result = (new EnglishStemmer()).normalize(text);
        } else {//Tokenisation par défault
            result = (new SimpleTokenizer()).normalize(text);
        }

        //Filtrages
        if (filterAccents) {
            result = enleverAccents(result);
        }

        if (filterNombres) {
            result = enleverNombres(result);
        }

        if (filterPonctuation) {
            result = enleverPonctuation(result);
        }

        if (filterStopWords) {
            try {
                result = enleverStopWords(result);
            } catch (IOException ex) {
            }
        }

        //Filtrer des cas particulier
        result = enleverCasParticuliers(result);

        return result;
    }

    protected String remplaceUrlsBy(String text, String replacer) {
        return text.replaceAll("http:\\S*", replacer);
    }

    protected String removeTags(String text) {
        return text.replaceAll("#\\S*", "").replaceAll("@\\S*", "");
    }

    protected ArrayList<String> enleverAccents(ArrayList<String> words) {
        Pattern pattern = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");

        ArrayList<String> results = new ArrayList<String>();

        for (String word : words) {
            String nfdNormalizedString = java.text.Normalizer.normalize(word, java.text.Normalizer.Form.NFD);
            results.add(pattern.matcher(nfdNormalizedString).replaceAll(""));
        }

        return results;
    }

    protected ArrayList<String> enleverNombres(ArrayList<String> words) {
        ArrayList<String> results = new ArrayList<String>();

        for (String word : words) {
            results.add(word.replaceAll("[0-9]+", ""));
        }

        return results;
    }

    protected ArrayList<String> enleverStopWords(ArrayList<String> words) throws IOException {

       initStopWordList();
       words.removeAll(stopWordList);

        return words;
    }
    
    protected void initStopWordList() throws IOException {
    	if(stopWordList == null) {
	    	String ENCODING = "UTF8";//Encodage du fichier stop word
	
	        //Lis le fichier
	        if (this.stopWordList == null) {
	            BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(this.stopWordsFilePath), ENCODING));
	            String line = null;
	
	            this.stopWordList = new ArrayList<String>();
	            while ((line = reader.readLine()) != null) {
	                stopWordList.add(line);
	                //System.out.println(line);//Bug bizare en lisant la première ligne, un caractère chelou est inséré avant le "a"
	            }
	            reader.close();
	        }
    	}
    }

    protected ArrayList<String> enleverPonctuation(ArrayList<String> words) {

        ArrayList<String> results = new ArrayList<String>();

        for (String word : words) {
            results.add(word.replaceAll("[^\\p{L}\\p{N}]", "").replaceAll("\\s+", ""));
        }

        return results;
    }

    protected ArrayList<String> enleverCasParticuliers(ArrayList<String> words) {

        ArrayList<String> special = new ArrayList<String>();
        special.add("");//Mot vide
        special.add("rt");//response to ?

        words.removeAll(special);

        return words;
    }

    @Override
    public String toString() {
        String str = "Normalizer \n" + normalisation.name() + " / " + encodage.name();
        str += " / Filtrage accent : " + filterAccents + " / Filtrage Nombre : " + filterNombres;
        str += "\n Filtrage SW : " + filterStopWords + " / Filtrage ponctuation : " + filterPonctuation;
        str += " / Filtrer Occurences uniques : " + filterOneOccurence + "\n";
        if (!replaceUrls) {
            str += "Ne pas remplacer les url";
        } else {
            str += "Remplacer les urls par : " + replaceUrlsBy;
        }

        return str;
    }
}
